/*
 * Brief: 系统日志模块
   
 *           输出方向: 	1 串口
 						2 本地文件
 						3 日志服务器

 	接口	syslog(int level,const char *fmt,...)

 		    	level：
				 	Emerg 				0
				 	Alert 				1
				 	Criti					2
				 	Errot				3
				 	Warn 				4
				 	Notice 				5
				 	Infor 				6
				 	Debug          			7	
			example:
					char *str="syslog tttt..\n";
					syslog(Debug,"%s\n",str);
 						 
 * by huhu
 * date:2015-6-29
 *mod by GTeng 
 *date:2015-10-22
 * 添加系统的syslog机制
 */
#include <syslog.h>
#include <stdlib.h>
#include <sys/time.h>
#include <pthread.h>
#include <stdarg.h>
#include <sys/stat.h>  
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
// #include <ovmsgproto.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

#include "syslog.h"

pthread_mutex_t mattr,net_mattr;

log_param log_serial;		//串口	
log_param log_server;		//日志服务器
log_param log_file;			//本地文件

#define		LOG_FORMAT		
#define		TIMESEC			timer.tv_sec-initial_timer.tv_sec
#define 	TIMEUSEC		timer.tv_usec


#define 	STA_BITS		0x1000
#define		LEVEL_BITS		0x0111

static struct timeval timer;
static struct timeval initial_timer;
// static struct p_net_ser_info	syslog_param;	

int syslog_sockfd;
struct sockaddr_in address;

//日志级别
static const char *_log_level[] =  
{  
    "emergency",  
    "alert",  
    "critical",  
    "error",  
    "warning",  
    "notice",  
    "info",  
    "debug"  
}; 

// 打开本地日志文件
void open_log_file(char * logfilename)
{	
	if((log_fp = fopen(logfilename,"r+")) < 0){
		perror("open SYSLOG");
		printf("open_log_file fail %s\n",logfilename);
		exit(2);
	}
	fseek(log_fp , 0 ,SEEK_END);
	//perror("open log file fseek");
}

//关闭日志文件
void close_log()
{
	fclose(log_fp);
}

/*
// udp client 初始化
void syslog_remote_udpserver(void)
{
  	uint16_t	syslog_port;
	uint32_t 	syslog_serverip;
	
	// 获取syslog服务器IP地址
	get_netser_info(&syslog_param);
	syslog_serverip 	= syslog_param.net_server.syslog_s.syslog_ip_addr;
	syslog_port 		= syslog_param.net_server.syslog_s.syslog_port;

    bzero(&address,sizeof(address));  
    address.sin_family=AF_INET;  
    address.sin_addr.s_addr=(syslog_serverip);
    address.sin_port=htons(syslog_port);  
	
	syslog_sockfd = socket(AF_INET,SOCK_DGRAM,0);//IPV4  SOCK_DGRAM 数据报套接字（UDP协议）  
}
*/

/*
 *  syslog 函数 ，供调用
 */
void ovsyslog(int level,const char *fmt,...)
{
	uint8_t syslog_buf[300];
	gettimeofday(&timer,NULL);
	time_t now;
	struct tm tm_now;
	time(&now);
	localtime_r(&now , &tm_now);
	va_list args;         //定义一个va_list类型的变量，用来储存单个参数
	va_start(args, fmt);  //使args指向可变参数的第一个参数  
    // 串口输出
	if(log_serial.enable && level >= log_serial.level){
		printf("[%d-%d %d:%d:%d][%s]:", tm_now.tm_mon+1,tm_now.tm_mday,
										tm_now.tm_hour, tm_now.tm_min,tm_now.tm_sec,
										_log_level[level]);
		vprintf(fmt,args);   
	}
	// 写入本地文件
	if(log_file.enable && level >= log_file.level){
		if(!pthread_mutex_trylock(&mattr)){
			//printf("write log file \n");
			fprintf(log_fp, "[%d-%d %d:%d:%d][%s]:", tm_now.tm_mon+1,tm_now.tm_mday,
										tm_now.tm_hour, tm_now.tm_min,tm_now.tm_sec,
										_log_level[level]);
			vfprintf(log_fp, fmt, args);
			pthread_mutex_unlock(&mattr);
		}
	}

	// 发送日志服务器
	if(log_server.enable){
		if(!pthread_mutex_trylock(&net_mattr)){
			vsnprintf(syslog_buf, sizeof(syslog_buf), fmt, args);
			sendto(syslog_sockfd,syslog_buf,strlen(syslog_buf),0,(struct sockaddr *)&address,sizeof(address)); 
			pthread_mutex_unlock(&net_mattr);
		}
	}
	fflush(log_fp);
	va_end(args);         //结束可变参数的获取
}

// 设置各输出方向日志级别
void set_logparam(int direct,int level,int enable)
{
	switch(direct)
	{
		case SERIAL:
			log_serial.enable = enable;
			log_serial.level  = level;
		break;
		case SYSLOG_SERVER:
			log_server.enable = enable;
			log_server.level  = level;
		break;
		case LOCAL_FILE:
			log_file.enable = enable;
			log_file.level  = level;
		break;
		default:
		break;
	}
}
/*
//从配置中获取个日志参数
void get_logparam()
{
	uint16_t syslog_level;
	get_netser_info(&syslog_param);
	syslog_level = syslog_param.net_server.syslog_s.syslog_level;
	log_serial.enable 	= syslog_level&STA_BITS;
	log_serial.level  	= syslog_level&LEVEL_BITS;
	log_file.enable 	= syslog_level&(STA_BITS<<4);
	log_file.level  	= syslog_level&(LEVEL_BITS<<4);
	log_server.enable 	= syslog_level&(STA_BITS<<8);
	log_server.level  	= syslog_level&(LEVEL_BITS<<8);
	
}
*/

// 日志模块初始化
void syslog_init(char * filename)
{	
	char *str="\nshowave app restart ok!\n";
	//openlog("FiberC", LOG_CONS ,0);
	/*获取初始时间*/
	gettimeofday(&initial_timer,NULL);
	/* initialize an attribute to default value */
	pthread_mutex_init(&mattr,NULL);
	pthread_mutex_init(&net_mattr,NULL);

	open_log_file(filename);
	
	/*设置syslog 输出方向，优先级*/
	set_logparam(SERIAL,Debug,DISABLE);
	set_logparam(LOCAL_FILE,Debug,ENABLE);
	set_logparam(SYSLOG_SERVER,Debug,DISABLE);
	
	// syslog_remote_udpserver();
	//syslog test
	ovsyslog(Debug,"%s\n",str);
	
}

//获取文件大小  
off_t  get_file_size(const char *path)  
{  
    off_t filesize = -1;      
    struct stat statbuff;  
    if(stat(path, &statbuff) < 0){  
        return filesize;  
    }else{  
        filesize = statbuff.st_size;  
    }  
    return filesize;  
}

//检查日志文件，满了则从头开始写 之前这个函数放到了信号处理函数里面，经过测试无法实现，之后
//将这个函数放到了轮询中的心跳发送里面测试成功。
void check_log_size()
{
	off_t log_size;
	int tempfd;

	log_size = get_file_size(SYSLOG);
	if(log_size > LOG_SIZE_LIMIT){
		if(fseek(log_fp,0,SEEK_SET)<0){
			printf("fseek error\n");
		}
	}else{
	}
	
	fflush(log_fp);
	//printf("log size %d\n",log_size);
}

void syslog_nomem()
{
	ovsyslog(Debug,"system have no mem");
}

